﻿Imports System.Reflection

<ComClass(ClsArc.ClassId, ClsArc.InterfaceId, ClsArc.EventsId)>
Public Class ClsArc

#Region "COM GUID"
    ' 这些 GUID 提供此类的 COM 标识 
    ' 及其 COM 接口。若更改它们，则现有的
    ' 客户端将不再能访问此类。
    Public Const ClassId As String = "e9965fc1-6ccb-49ec-b1aa-e1997bf04205"
    Public Const InterfaceId As String = "45099541-036a-4d84-9cb7-b8dfbb95849b"
    Public Const EventsId As String = "0ea8d799-1747-4d68-a662-f447f86788f3"
#End Region

    ' 可创建的 COM 类必须具有一个不带参数的 Public Sub New() 
    ' 否则， 将不会在 
    ' COM 注册表中注册此类，且无法通过
    ' CreateObject 创建此类。
    Public Sub New()
        MyBase.New()
    End Sub

#Region "字段以及属性"
    Private _ce As ClsPoint2d
    Public Property Center As ClsPoint2d
        Get
            Return _ce
        End Get
        Set(ByVal value As ClsPoint2d)
            _ce = value
        End Set
    End Property

    Private _r As Double
    Public Property Radius() As Double
        Get
            Return _r
        End Get
        Set(ByVal value As Double)
            _r = value
        End Set
    End Property

    Private _startAngle As Double
    Public Property StartAngle() As Double
        Get
            Return _startAngle
        End Get
        Set(ByVal value As Double)
            _startAngle = value
        End Set
    End Property

    Private _endAngle As Double
    Public Property EndAngle() As Double
        Get
            Return _endAngle
        End Get
        Set(ByVal value As Double)
            _endAngle = value
        End Set
    End Property

    Public ReadOnly Property TotalAngle As Double
        Get
            If Me.IsClockWise Then
                Return IIf(Me.EndAngle > Me.StartAngle, Me.EndAngle - Me.StartAngle, Me.EndAngle - Me.StartAngle)
            Else
                Return IIf(Me.EndAngle > Me.StartAngle, Me.EndAngle - Me.StartAngle, Me.EndAngle - Me.StartAngle)
            End If
        End Get
    End Property
    Public ReadOnly Property StartPoint As ClsPoint2d
        Get
            Dim v As New ClsVector2d
            v.CreatorUnitVictor2dByAngle(Me.StartAngle)
            Return Me.Center.Add(v.Multiply(Me.Radius))
        End Get
    End Property

    Public ReadOnly Property EndPoint As ClsPoint2d
        Get
            Dim v As New ClsVector2d
            v.CreatorUnitVictor2dByAngle(Me.EndAngle)
            Return Me.Center.Add(v.Multiply(Me.Radius))
        End Get
    End Property

    Public ReadOnly Property IsMajorArc As Boolean
        Get
            Return Me.TotalAngle > Math.PI
        End Get
    End Property
    Public ReadOnly Property IsClockWise As Boolean
        Get
            Dim mathHelper As New ClsMath
            If mathHelper.IsClockWise(Me.EndPoint, Me.Center, Me.StartPoint) = 旋转方向.ClockWise Then
                Return True
            Else
                Return False
            End If
        End Get
    End Property
    Public ReadOnly Property ArcBulge As Double
        Get
            Return IIf(Me.IsClockWise, (Math.Tan((0.25 * Me.TotalAngle)) * -1), Math.Tan((0.25 * Me.TotalAngle)))
        End Get
    End Property

    Public ReadOnly Property ArcLength As Double
        Get
            Return (Me.TotalAngle * Me.Radius)
        End Get
    End Property

    Public ReadOnly Property MidPoint As ClsPoint2d
        Get
            Return IIf(Me.IsClockWise, Me.StartPoint.Rotate((Me.TotalAngle * 0.5), Me.Center), Me.EndPoint.Rotate((Me.TotalAngle * 0.5), Me.Center))
        End Get

    End Property
#End Region

#Region "构造函数"
    ''' <summary>
    ''' 三点画圆弧
    ''' </summary>
    ''' <param name="startPoint">起点</param>
    ''' <param name="endPoint">终点</param>
    ''' <param name="mPoint2d">圆弧的中点</param>
    Public Sub CreatorBy3Points(ByVal startPoint As ClsPoint2d, ByVal endPoint As ClsPoint2d, ByVal mPoint2d As ClsPoint2d)
        Dim x1 As Double = startPoint.X
        Dim y1 As Double = startPoint.Y
        Dim x2 As Double = endPoint.X
        Dim y2 As Double = endPoint.Y
        Dim x3 As Double = mPoint2d.X
        Dim y3 As Double = mPoint2d.Y
        Dim e As Double = (2 * (x2 - x1))
        Dim f As Double = (2 * (y2 - y1))
        Dim g As Double = ((((x2 * x2) - (x1 * x1)) + (y2 * y2)) - (y1 * y1))
        Dim a As Double = (2 * (x3 - x2))
        Dim b As Double = (2 * (y3 - y2))
        Dim c As Double = ((((x3 * x3) - (x2 * x2)) + (y3 * y3)) - (y2 * y2))
        Me.Center = New ClsPoint2d() With {.X = ((g * b) - (c * f)) / ((e * b) - (a * f)), .Y = ((g * a) - (c * e)) / ((a * f) - (b * e))}
        Me.Radius = Math.Sqrt((((Me.Center.X - x1) * (Me.Center.X - x1)) + ((Me.Center.Y - y1) * (Me.Center.Y - y1))))
        Me.StartAngle = Me.Center.GetVector2dTo(startPoint).AngelToXAxis
        Me.EndAngle = Me.Center.GetVector2dTo(endPoint).AngelToXAxis
    End Sub

    Public Sub CreatorByCenterStartAngleEndAngle(center As ClsPoint2d, startangle As Double, endangle As Double, r As Double)
        Me.Center = center
        Me.StartAngle = startangle
        Me.EndAngle = endangle
        Me.Radius = r
    End Sub
    Public Sub CreatorByCenterStartPtEndPt(center As ClsPoint2d, startpt As ClsPoint2d, endpt As ClsPoint2d)
        Me.Center = center
        Me.StartAngle = Me.Center.GetVector2dTo(startpt).AngelToXAxis
        Me.EndAngle = Me.Center.GetVector2dTo(endpt).AngelToXAxis
        Me.Radius = Me.Center.GetDistanceTo(startpt)
    End Sub

    Public Sub CreatorByStartPtEndPtBulgeValue(startpt As ClsPoint2d, endpt As ClsPoint2d, bulgeValue As Double)
        Dim m As New ClsMath
        Me.Center = m.GetArcCenter(startpt, endpt, bulgeValue)
        Me.StartAngle = Me.Center.GetVector2dTo(If(bulgeValue < 0, endpt, startpt)).AngelToXAxis
        Me.EndAngle = Me.Center.GetVector2dTo(If(bulgeValue < 0, startpt, endpt)).AngelToXAxis
        Me.Radius = Me.Center.GetDistanceTo(startpt)
    End Sub
#End Region

#Region "转换成完整的圆"
    Public Function ToCircle() As ClsCircle
        Return New ClsCircle With {.Center = Me.Center, .Radius = Me.Radius}
    End Function
#End Region

#Region "与cad对象互相转化"
    Public Function CreateFromAcadObject(acArc As Object) As Boolean
        If TypeName(acArc) = $"IAcadArc" Then
            Dim p As New ClsPoint2d
            p.CreatorByArray(acArc.Center)
            Me.Center = p
            Me.StartAngle = acArc.StartAngle
            Me.EndAngle = acArc.EndAngle
            Me.Radius = acArc.Radius
            Return True
        Else
            Return False
        End If
    End Function

    Public Function ConvertToAcadEntity(acLayout As Object, Elevation As Double) As Object
        Return acLayout.AddArc(Me.Center.To3DArray(), Me.Radius, Me.StartAngle, Me.EndAngle)
    End Function
#End Region

#Region "Clone"
    Public Function Clone() As ClsArc

        Dim t As Type = Me.GetType()
        Dim setProps As List(Of PropertyInfo) = t.GetProperties.Where(Function(p) p.CanWrite).ToList()
        Dim rtnObj = Activator.CreateInstance(t)
        For Each p As PropertyInfo In setProps
            p.SetValue(rtnObj, p.GetValue(Me, Nothing), Nothing)
        Next
        Return DirectCast(rtnObj, ClsArc)

    End Function

#End Region

End Class


